package com.ice.framework.web.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.ice.framework.common.context.CustomerUserContext;
import com.ice.framework.common.context.RequestContext;
import com.ice.framework.common.context.RequestContextThreadLocal;
import com.ice.framework.web.helper.RequestHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.UUID;

/**
 * @author wangwei
 * @Date 2021/12/22 17:48
 */
@ControllerAdvice
public class RequestBodyAdviceHandler implements RequestBodyAdvice {

    public RequestBodyAdviceHandler() {
    }

    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        Method method = methodParameter.getMethod();
        Class<?> declaringClass = method.getDeclaringClass();
        return (isRestController(declaringClass) || (isController(declaringClass) && isResponseBody(methodParameter)));
    }

    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        return inputMessage;
    }

    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        this.writeRequestLog(body, inputMessage, parameter, targetType, converterType);
        return body;
    }

    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        this.writeRequestLog(body, inputMessage, parameter, targetType, converterType);
        return body;
    }


    private void writeRequestLog(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        HttpServletRequest request = RequestHelper.getRequest();
        //设置请求开始时间
        request.setAttribute(RequestContext.REQUEST_STARTTIME, System.currentTimeMillis());
        //header中是否存在requestId(请求传递)
        String requestId = request.getHeader(RequestContext.REQUEST_ID);
        //首次请求,创建请求标识
        if (StringUtils.isEmpty(requestId)) {
            requestId = UUID.randomUUID().toString().replaceAll("-", "");
        }
        //将UUID设置到Request的参数中
        request.setAttribute(RequestContext.REQUEST_ID, requestId);

        Method method = parameter.getMethod();

        StringBuilder info = new StringBuilder("==>\n");
        info.append("[*=请求requestID=]>: ").append(requestId).append("\n");
        info.append("[==请求地址=======]>: ").append(request.getRequestURL().toString()).append("\n");
        info.append("[==请求方法=======]>: ").append(request.getMethod()).append("\n");
        info.append("[==操作用户=======]>: ").append(CustomerUserContext.getCurrentUserCode()).append("\n");
        info.append("[==客户IP========]>: ").append(RequestHelper.getClientIP()).append("\n");
        info.append("[==映射方法=======]>: ").append(method.getDeclaringClass().getName()).append(".").append(method.getName()).append("\n");
        if (body == null) {
            info.append("[==请求参数=======]>: ").append("该接口未定义参数或参数为空");
        } else if (converterType == FastJsonHttpMessageConverter.class) {
            info.append("[==请求参数=======]>: ").append(JSON.toJSONString(body));
        } else {
            info.append("[==请求参数=======]>: ").append(converterType);
        }

        info.append("\n");
        request.setAttribute("_REQUEST_LOG_INFO_", info);
        RequestContextThreadLocal.setRequestId(requestId);
    }

    private boolean isRestController(Class<?> declaringClass) {
        RestController annotation = (RestController) declaringClass.getAnnotation(RestController.class);
        return annotation != null;
    }

    private boolean isController(Class<?> declaringClass) {
        Controller annotation = declaringClass.getAnnotation(Controller.class);
        return annotation != null;
    }

    private boolean isResponseBody(MethodParameter returnType) {
        ResponseBody methodAnnotation = (ResponseBody) returnType.getMethodAnnotation(ResponseBody.class);
        return methodAnnotation != null;
    }
}
